<template>
  <div id="container">
    <div style="height: 55px;background-color: #444444;">上面布局</div>
    <!-- 下 -->
    <div>
      <div id="left" style="position: absolute;top: 60px;background-color: #444444;width: 195px;">下面左侧布局</div>
      <div id="webgl" style="position: absolute;top: 60px;left: 200px;background-color: #444444;">
        <div style="color: #ff0000;z-index:2;position: relative;">红色</div>
      </div>
    </div>
  </div>
</template>

<script setup>
import * as THREE from 'three'
// 引入轨道控制器扩展库OrbitControls.js
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// 引入dat.gui.js的一个类GUI
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { onMounted } from 'vue';
// 实例化一个gui对象
const gui = new GUI();
//改变交互界面style属性
gui.domElement.style.right = '0px';
gui.domElement.style.width = '300px';

const width = window.innerWidth - 200;
const height = window.innerHeight - 60;

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
onMounted(() => {
  document.getElementById('left').style.height = height + 'px';
  document.getElementById('webgl').style.width = width + 'px';
  document.getElementById('webgl').style.height = height + 'px';

  document.getElementById('webgl').appendChild(renderer.domElement)
})

// document.body.appendChild(renderer.domElement);
//创建一个长方体几何对象Geometry
// //BoxGeometry：长方体
// const geometry = new THREE.BoxGeometry(50, 50, 50);
//创建一个空的几何体对象
const geometry = new THREE.BoxGeometry(100, 100, 100);
// canvas画布绝对定位
renderer.domElement.style.position = 'absolute';
renderer.domElement.style.top = '0px';
renderer.domElement.style.left = '0px';
renderer.domElement.style.zIndex = 10;
// 立方体纹理加载器CubeTextureLoader
// TextureLoader返回Texture
// CubeTextureLoader返回CubeTexture

// 通过前面学习大家知道，通过纹理贴图加载器TextureLoader的.load()方法加载一张图片可以返回一个纹理对象Texture。

// 立方体纹理加载器CubeTextureLoader的.load()方法是加载6张图片，返回一个立方体纹理对象CubeTexture。

// 立方体纹理对象CubeTexture的父类是纹理对象Texture。
// #
// CubeTextureLoader加载环境贴图

// CubeTextureLoader加载环境贴图

// 所谓环境贴图，就是一个模型周围的环境的图像，比如一间房子，房子的上下左右前后分别拍摄一张照片，就是3D空间中6个角度方向的照片。

// 加载环境贴图
// 加载周围环境6个方向贴图
// 上下左右前后6张贴图构成一个立方体空间
// 'px.jpg', 'nx.jpg'：x轴正方向、负方向贴图  p:正positive  n:负negative
// 'py.jpg', 'ny.jpg'：y轴贴图
// 'pz.jpg', 'nz.jpg'：z轴贴图
const textureCube = new THREE.CubeTextureLoader()
  .setPath('static/cube/')
  .load(['floor1.jpg', 'floor1.jpg', 'floor1.jpg', 'floor1.jpg', 'floor1.jpg', 'floor1.jpg']);
// .load(['front.jpg', 'back.jpg', 'left.jpg', 'right.jpg', 'up.jpg', 'down.jpg']);
// CubeTexture表示立方体纹理对象，父类是纹理对象Texture 
// 加载环境贴图
// 加载周围环境6个方向贴图
// 上下左右前后6张贴图构成一个立方体空间
// 'px.jpg', 'nx.jpg'：x轴正方向、负方向贴图  p:正positive  n:负negative
// 'py.jpg', 'ny.jpg'：y轴贴图
// 'pz.jpg', 'nz.jpg'：z轴贴图

const material = new THREE.MeshPhysicalMaterial({
  color: 0x0000ff, //材质颜色
  // wireframe: true //线条模式渲染mesh对应的三角形数据
  // side: THREE.FrontSide, //默认只有正面可见

  //金属度
  //默认是0.5,范围是0到1之间。木材或石材用0,金属使用1。
  metalness: 1.0,//金属度属性

  //表面粗糙度
  //默认0.5，范围是0~1之间,0表示平滑的镜面反射,1表示完全漫反射,
  roughness: 0.9,//表面粗糙度

  // envMapIntensity：控制环境贴图对mesh表面影响程度
  //默认值1, 设置为0相当于没有环境贴图
  envMapIntensity: 1.0, //环境贴图对Mesh表面影响程度
  envMap: textureCube, //设置pbr材质环境贴图

  // .transmission的值范围是从0.0到1.0。默认值为0.0
  transmission: 1.5, //玻璃材质透光率，transmission替代opacity

  // 非金属材料的折射率从1.0到2.333。默认值为1.5。
  ior: 1.5,//折射率\

  //   （1）清漆层clearcoat和清漆层粗糙度.clearcoatRoughness

  // clearcoat：模拟物体表面一层透明图层，类似车漆的抛光打蜡，具有透明和反光特性，值越大反光效果越好。clearcoatRoughness，值越大反光效果越弱。
  clearcoat: 1.0,//半透明涂层的厚度，默认是0，范围是0~1m
  clearcoatRoughness: 0.1,//半透明涂层表面的粗糙度，默认是0，范围是0~1
});
//如果renderer.outputEncoding=THREE.sRGBEncoding;环境贴图需要保持一致
textureCube.encoding = THREE.sRGBEncoding;

const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//  本地(局部)坐标和世界坐标
mesh.position.x = 50
const scene = new THREE.Scene()
scene.add(mesh)
// 添加一个辅助网格地面
const gridHelper = new THREE.GridHelper(10, 10, 0x004444, 0x004444);
scene.add(gridHelper)
// 环境贴图纹理对象textureCube作为.environment属性值,影响所有模型
scene.environment = textureCube; // 设置环境贴图
scene.background = textureCube; // 设置环境
// AxesHelper：辅助观察的坐标系
const axesHelper = new THREE.AxesHelper(20);
scene.add(axesHelper);
// 实例化一个透视投影相机对象
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000：远裁截面
// // 超出视锥体远裁界面的范围的会被剪裁掉，不渲染  可以调整far参数适配 所以要看全部就把远裁面拉高10000
// const camera = new THREE.PerspectiveCamera(30, window.innerWidth / window.innerHeight, 1, 10000);
// 200表示左侧div元素宽度195px+间距5px
const width2 = window.innerWidth - 200; //canvas画布高度
//60表示顶部div元素高度55px+间距5px
const height2 = window.innerHeight - 60; //canvas画布宽度
const camera = new THREE.PerspectiveCamera(30, width2 / height2, 1, 3000);
renderer.setSize(width2, height2);


// 创建光源
const light = new THREE.AmbientLight(0xffffff);
scene.add(light);
//相机在Three.js三维坐标系中的位置
// 根据需要设置相机位置具体值
camera.position.set(16, 100, 16);
// camera.lookAt(mesh.position);//指向mesh对应的位置
// // 改变相机观察目标点
camera.lookAt(10, 0, 0);
// 设置相机控件轨道控制器OrbitControls
// 创建渲染器对象
// 设置渲染器锯齿属性.antialias的值可以直接在参数中设置，也可通过渲染器对象属性设置
//环境光:没有特定方向，整体改变场景的光照明暗


const pointLight = new THREE.PointLight(0xffffff, 1.0);
pointLight.decay = 0.0;//设置光源不随距离衰减
//点光源位置
pointLight.position.set(200, 200, 300);//点光源放在x轴上
scene.add(pointLight); //点光源添加到场景中

//环境光:没有特定方向，整体改变场景的光照明暗
const ambient = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambient);

// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
// 设置光源的方向：通过光源position属性和目标指向对象的position属性计算
directionalLight.position.set(-80, -100, -50);
// 方向光指向对象网格模型mesh，可以不设置，默认的位置是0,0,0
directionalLight.target = mesh;
scene.add(directionalLight);
// DirectionalLightHelper：可视化平行光
const dirLightHelper = new THREE.DirectionalLightHelper(directionalLight, 5, 0xff0000);
scene.add(dirLightHelper);

// 不同硬件设备的屏幕的设备像素比window.devicePixelRatio值可能不同
console.log('查看当前屏幕设备像素比', window.devicePixelRatio);
// 或者直接设置参数  renderer.antialias = true

// 如果你遇到你的canvas画布输出模糊问题，注意设置renderer.setPixelRatio(window.devicePixelRatio)。
// 注意：注意你的硬件设备设备像素比window.devicePixelRatio刚好是1，那么是否执行.setPixelRatio()不会有明显差异，不过为了适应不同的硬件设备屏幕，通常需要执行该方法。
// 获取你屏幕对应的设备像素比.devicePixelRatio告诉threejs,以免渲染模糊问题
renderer.setPixelRatio(window.devicePixelRatio);

renderer.setClearColor(0x444444, 1); //设置背景颜色

function render() {
  // console.log('camera', camera.position)
  renderer.render(scene, camera); //执行渲染操作
  requestAnimationFrame(render);//请求再次执行渲染函数render，渲染下一帧
}
render();

const controls = new OrbitControls(camera, renderer.domElement);
// 相机控件.target属性在OrbitControls.js内部表示相机目标观察点，默认0,0,0
// console.log('controls.target', controls.target);
controls.target.set(10, 0, 0);
controls.update();//update()函数内会执行camera.lookAt(controls.targe)


// 如果OrbitControls改变了相机参数，重新调用渲染器渲染三维场景
controls.addEventListener('change', function () {
  // 浏览器控制台查看相机位置变化
  // console.log('camera.position', camera.position);
  // 渲染循环和相机控件OrbitControls

  // 设置了渲染循环, 相机控件OrbitControls就不用再通过事件change执行renderer.render(scene, camera);，毕竟渲染循环一直在执行renderer.render(scene, camera);。
  // renderer.render(scene, camera); //执行渲染操作
});//监听鼠标、键盘事件
// onresize 事件会在窗口被调整大小时发生
// window.onresize = function () {
//   // 重置渲染器输出画布canvas尺寸
//   renderer.setSize(window.innerWidth, window.innerHeight);
//   // 全屏情况下：设置观察范围长宽比aspect为窗口宽高比
//   camera.aspect = window.innerWidth / window.innerHeight;
//   // 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
//   // 但是不会每渲染一帧，就通过相机的属性计算投影矩阵(节约计算资源)
//   // 如果相机的一些属性发生了变化，需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
//   camera.updateProjectionMatrix();
// };
// 画布跟随窗口变化
window.onresize = function () {
  const width = window.innerWidth - 200; //canvas画布高度
  const height = window.innerHeight - 60; //canvas画布宽度
  renderer.setSize(width, height);
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
};

gui.add(mesh.material, 'metalness', 0, 1).name('金属度属性')
gui.add(mesh.material, 'roughness', 0, 1).name('表面粗糙度')
gui.add(mesh.material, 'transmission', 0, 1).name('玻璃材质透光率，transmission替代opacity')
gui.add(mesh.material, 'ior', 0, 3).name('折射率')
gui.add(mesh.material, 'envMapIntensity', 0, 10).name('环境贴图对Mesh表面影响程度')
gui.add(mesh.material, 'clearcoat', 0, 1).name('清漆度')
gui.add(mesh.material, 'clearcoatRoughness', 0, 1)

</script> 
<style scoped>
#container {
  width: 100%;
  height: 100%;
}

#canvas {
  width: 100%;
  height: 100%;
  position: relative;
  top: 0;
  left: 0;
}
</style>